package xyz.xiaoshengfu.xrpc.spring;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.w3c.dom.Element;

import xyz.xiaoshengfu.xrpc.config.ApplicationConfig;
import xyz.xiaoshengfu.xrpc.config.ProtocolConfig;
import xyz.xiaoshengfu.xrpc.config.ReferenceBean;
import xyz.xiaoshengfu.xrpc.config.RegistryConfig;
import xyz.xiaoshengfu.xrpc.config.ServiceBean;
import xyz.xiaoshengfu.xrpc.data.XRpcResources;

/**
 * <p>Title: XRpcBeanDefinitionParser</p>
 * <p>Description: 解析xRPC配置文件</p>
 * @author xiaoshengfu(2439323118@qq.com)
 * @date 2020年3月24日
 */
public class XRpcBeanDefinitionParser implements BeanDefinitionParser {

	private final Class<?> beanClass;

	public XRpcBeanDefinitionParser(Class<?> beanClass) {
		super();
		this.beanClass = beanClass;
	}

	@Override
	public BeanDefinition parse(Element element, ParserContext parserContext) {
		RootBeanDefinition rootBeanDefinition = new RootBeanDefinition();
		rootBeanDefinition.setBeanClass(beanClass);
		if (ApplicationConfig.class.equals(beanClass)) {
			String name = element.getAttribute("name");
			if (StringUtils.isNotBlank(name)) {
				XRpcResources.xRpcConfig.setApplicationConfig(new ApplicationConfig(name));
				parserContext.getRegistry().registerBeanDefinition("xRpcSpringApplicationListener",
						new RootBeanDefinition(XRpcSpringApplicationListener.class));
			} else {
				throw new RuntimeException("");
			}

		} else if (ProtocolConfig.class.equals(beanClass)) {
			String name = element.getAttribute("name");
			String port = element.getAttribute("port");
			if ("xrpc".equals(name) && StringUtils.isNotBlank(port)) {
				XRpcResources.xRpcConfig.setProtocolConfig(
						new ProtocolConfig(name, StringUtils.isNotBlank(port) ? new Integer(port) : 6379));
			}

		} else if (RegistryConfig.class.equals(beanClass)) {
			String protocol = element.getAttribute("protocol");
			String address = element.getAttribute("address");
			String port = element.getAttribute("port");
			String password = element.getAttribute("password");
			if ("redis".equals(protocol) && StringUtils.isNotBlank(address)) {
				XRpcResources.xRpcConfig
						.setRegistryConfig(new RegistryConfig(protocol, address, new Integer(port), password));
			}

		} else if (ReferenceBean.class.equals(beanClass)) {
			String referenceInterface = element.getAttribute("interface");
			String id = element.getAttribute("id");
			String timeout = element.getAttribute("timeout");
			if (StringUtils.isNotBlank(id) && StringUtils.isNotBlank(referenceInterface)
					&& StringUtils.isNotBlank(timeout)) {
				XRpcResources.xRpcConfig.getReferenceBeanList()
						.add(new ReferenceBean(referenceInterface, id, new Integer(timeout)));
				Class<?> clazz = null;
				try {
					clazz = Class.forName(referenceInterface);
				} catch (ClassNotFoundException e) {
					e.printStackTrace();
				}
				if (clazz != null) {
					BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(clazz);
					GenericBeanDefinition definition = (GenericBeanDefinition) builder.getRawBeanDefinition();
					definition.getConstructorArgumentValues().addGenericArgumentValue(referenceInterface);
					definition.setBeanClass(XrpcServiceFactory.class);
					definition.setAutowireMode(GenericBeanDefinition.AUTOWIRE_BY_NAME);
					parserContext.getRegistry().registerBeanDefinition(id, definition);
				}

			}
		} else if (ServiceBean.class.equals(beanClass)) {
			String serviceInterface = element.getAttribute("interface");
			String ref = element.getAttribute("ref");
			String weight = element.getAttribute("weight");
			if (StringUtils.isNotBlank(serviceInterface) && StringUtils.isNotBlank(ref)) {
				Integer iweight = null;
				if (StringUtils.isNotBlank(weight)) {
					iweight = new Integer(weight);
					if (iweight < 1) {
						iweight = 1;
					}
				} else {
					iweight = 1;
				}
				XRpcResources.xRpcConfig.getServiceBeanList().add(new ServiceBean(serviceInterface, ref, iweight));
			}
		}
		return rootBeanDefinition;
	}

}